#include "VRecurCarrySaveAdder.h"
#include "verilated.h"
#include <iostream>
#include <vector>
#include <random>
#include <cassert>

// Helper function to print test results
void printTest(const std::vector<uint32_t>& inputs, uint32_t expected, uint32_t actual) {
    std::cout << "Inputs: ";
    for (auto input : inputs) {
        std::cout << input << " ";
    }
    std::cout << "\nExpected: " << expected << ", Got: " << actual;
    std::cout << (expected == actual ? " ✓" : " ✗") << "\n\n";
}

int main(int argc, char** argv) {
    // Initialize Verilator
    Verilated::commandArgs(argc, argv);
    
    // Create an instance of our module under test
    VRecurCarrySaveAdder* csa = new VRecurCarrySaveAdder;
    
    // Test parameters
    const int WIDTH = 4;
    const int LEVEL = 3;
    const int OPERS = 1 << LEVEL;  // 8 operands
    
    // Random number generator
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, (1 << WIDTH) - 1);
    
    // Test cases
    std::vector<std::vector<uint32_t>> test_cases;
    
    // Add some specific test cases
    test_cases.push_back({1, 1, 1, 1, 1, 1, 1, 1});  // All ones
    test_cases.push_back({0, 0, 0, 0, 0, 0, 0, 0});  // All zeros
    test_cases.push_back({15, 15, 15, 15, 15, 15, 15, 15});  // All max values
    
    // Add some random test cases
    for (int i = 0; i < 10; i++) {
        std::vector<uint32_t> inputs;
        for (int j = 0; j < OPERS; j++) {
            inputs.push_back(dis(gen));
        }
        test_cases.push_back(inputs);
    }
    
    // Run tests
    for (const auto& test : test_cases) {
        // Set inputs
        uint32_t packed_op = 0;
        for (int i = 0; i < OPERS; i++) {
            // Pack each WIDTH-bit value into the correct position
            packed_op |= (test[i] & ((1 << WIDTH) - 1)) << (i * WIDTH);
        }
        csa->Op = packed_op;
        
        // Evaluate model
        csa->eval();
        
        // Calculate expected result
        uint32_t expected = 0;
        for (auto val : test) {
            expected += val;
        }
        
        // Get actual result
        uint32_t actual = (csa->cout << (WIDTH + LEVEL)) | csa->S;
        
        // Print and verify results
        printTest(test, expected, actual);
        assert(expected == actual);
    }
    
    // Clean up
    delete csa;
    
    std::cout << "All tests passed!\n";
    return 0;
} 